﻿using System;
using System.Data;
using System.Data.SqlServerCe;

namespace RFServer.Database
{
    #region Исключение, бросаемые драйвером

    public class EDatabase : Exception
    {
        // Неизвестная ошибка при работе с базой данных

        public EDatabase(string msg)
            : base(msg)
        {
        }
    }

    public class EDatabaseObjectAlreadyExists : EDatabase
    {
        // Объект уже существует в базе данных
        // (нарушено ограничение unique)

        public EDatabaseObjectAlreadyExists(string msg)
            : base(msg)
        {
        }
    }

    public class EDatabaseTableEmpty : EDatabase
    {
        // Результат операции SELECT - пустая таблица

        public EDatabaseTableEmpty(string msg)
            : base(msg)
        {
        }
    }

    #endregion

    public class CEDriver
    {
        private SqlCeConnection conn;
        private string ConnectionString;
        public string Error { get; private set; }

        /// <summary>
        /// Конструктор инициализирует подключение к базе данных, формируя
        /// Connection string
        /// </summary>
        /// <param name="Database">Имя файла базы данных</param>

        public CEDriver(string Database)
        {
            ConnectionString = "Data Source = \"" + Database + "\";";

            Setup.Log("[database]: Using " + Database);

            try
            {
                conn = new SqlCeConnection(ConnectionString);
            }
            catch (SqlCeException e)
            {
                error("Constructor error: " + e.Message);
            }
        }

        /// <summary>
        /// Функция создает базу данных целиком
        /// </summary>

        public void CreateDatabase()
        {
            SqlCeEngine engine = new SqlCeEngine(ConnectionString);
            engine.CreateDatabase();
        }

        /// <summary>
        /// Выполнение SQL-оператора
        /// </summary>
        /// <param name="query">SQL-оператор (не SELECT)</param>
        /// <returns></returns>

        public void Execute(string query)
        {
            try
            {
                SqlCeCommand cmd = new SqlCeCommand(query, conn);

                cmd.ExecuteNonQuery();
            }
            catch (SqlCeException e)
            {
                if (e.Message.Contains("A duplicate value cannot be"))
                    error_exists("Unique constraint error: " + e.Message);
                else
                    error("Query error: " + e.Message);
            }
        }

        /// <summary>
        /// Выполняет оператор SELECT
        /// </summary>
        /// <returns>Объект DataTable со всеми данными из таблицы</returns>

        public DataTable Select(string select, string table)
        {
            try
            {
                SqlCeDataAdapter da = new SqlCeDataAdapter(select, conn);

                DataSet ds = new DataSet();

                da.Fill(ds, table);

                DataTable result = ds.Tables[table];

                try
                {
                    object test = result.Rows[0][0];
                }
                catch (IndexOutOfRangeException)
                {
                    throw new EDatabaseTableEmpty("Table is empty");
                }

                return result;

            }
            catch (SqlCeException e)
            {
                error("Select error: " + e.Message);
                return null;
            }
        }

        /// <summary>
        /// Выполняет оператор SELECT, результатом которого может быть
        /// только таблица, состоящая из одного числа
        /// </summary>
        /// <returns>id элемента</returns>

        public int SelectID(string select, string table)
        {
            DataTable dt = Select(select, table);
            int result = 0;

            try
            {
                result = (int)dt.Rows[0][0];
            }
            catch(IndexOutOfRangeException)
            {
                throw new EDatabaseTableEmpty("ID does not exists");
            }

            return result;
        }

        ////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Соединение с базой данных
        /// </summary>
        /// <returns></returns>

        public void Connect()
        {
            try
            {
                if (conn.State == ConnectionState.Closed)
                    conn.Open();
            }
            catch (SqlCeException e)
            {
                error("Connection error: " + e.ToString());
            }
        }

        /// <summary>
        /// Разрыв соединения с базой данных
        /// </summary>
        /// <returns></returns>

        public void Disconnect()
        {
            try
            {
                conn.Close();
            }
            catch (SqlCeException e)
            {
                error("Disconnect error: " + e.ToString());
            }
        }

        /// <summary>
        /// Генерация ошибок
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>

        private void error(string msg)
        {
            Error = msg;

            throw new EDatabase(msg);
        }

        /// <summary>
        /// Генерация ошибок
        /// Объект уже существует в базе данных
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>

        private void error_exists(string msg)
        {
            Error = msg;

            throw new EDatabaseObjectAlreadyExists(msg);
        }
    }
}
